// Learn TypeScript:
//  - https://docs.cocos.com/creator/manual/en/scripting/typescript.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html

import Cell, {CellType} from "./Cell";
import ClickBox from "./ClickBox";

const {ccclass, property} = cc._decorator;


const WIDTH = 143;

@ccclass
export default class NewClass extends cc.Component {

    @property([cc.SpriteFrame])
    numFrames: cc.SpriteFrame[] = [];

    @property([cc.SpriteFrame])
    linkFrames: cc.SpriteFrame[] = [];

    @property(cc.Node)
    bgLayer: cc.Node = null;

    @property([cc.SpriteFrame])
    bomFrames: cc.SpriteFrame[] = [];

    @property(cc.Label)
    comboLabel: cc.Label = null;

    @property(cc.Label)
    scoreLabel: cc.Label = null;

    @property(cc.Label)
    topScoreLabel: cc.Label = null;

    @property(ClickBox)
    clickBox: ClickBox = null;

    @property(cc.Label)
    combineLabel: cc.Label = null;

    @property(cc.Label)
    cutLabel: cc.Label = null;

    @property(cc.Node)
    resultNode: cc.Node = null;

    @property(cc.Label)
    resultScoreLabel: cc.Label = null;

    @property(cc.Label)
    resultTopScoreLabel: cc.Label = null;

    @property(cc.Node)
    resultHintNode: cc.Node = null;

    numCombine = 2; // 道具1的数量
    numCut = 2; // 道具2的数量

    mergeTimes = 0; // 合并次数

    bgFrames: cc.Node[]; // 25个高亮框

    cells: Cell[]; // 25个格子

    touchable = true; // 是否可触摸操作

    dragCell: Cell = null;  // 当前拖拽的格子
    dragTween: cc.Tween;
    dragOffset: cc.Vec2; // 拖拽的偏移

    bombCell: Cell = null; // 当前点击的炸弹

    combo = 0;  // 连击次数
    score = 0; // 当前分数

    start() {
        this.bgFrames = this.bgLayer.children.map(v => v.getChildByName('iframe'));
        this.updateItemLabelText();
        this.cells = new Array(25);
        this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.node.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
        this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
        this.topScoreLabel.string = '' + (parseInt(cc.sys.localStorage.getItem('topScore')) | 0);


        // 创建初始格子
        for (let i = 0; i < 5; i++) {
            this.createInitCell();
        }

    }

    protected onDisable() {
        this.node.off(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.node.off(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.node.off(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
        this.node.off(cc.Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
    }

    onTouchStart(e: cc.Event.EventTouch) {
        if (!this.touchable) {
            return;
        }
        let idx = this.touchToIdx(e.getLocation());
        if (idx >= 0) {
            let cell = this.cells[idx];
            if (cell) {
                if (cell.type == CellType.数字) {
                    this.dragCell = cell;

                    cell.node.zIndex = 100;

                    let loc = this.node.convertToNodeSpaceAR(e.getLocation());

                    this.dragOffset = cc.v2(0, 60);

                    this.dragTween?.stop();
                    this.dragTween = cc.tween(this.dragCell.node)
                        .to(0.2, {position: cc.v3(loc.x + this.dragOffset.x, loc.y + this.dragOffset.y, 0)}, {easing: 'sineOut'})
                        .start();

                    cc.tween(this.dragCell.node)
                        .to(0.1, {scale: 0.9}, {easing: 'sineOut'})
                        .to(0.1, {scale: 1}, {easing: 'sineOut'})
                        .start();
                }
                let linkCell: Cell = null;
                if (cell.type == CellType.连接部分) {
                    if (cell.pair.type == CellType.横向连接) {
                        this.dragOffset = cc.v2(-WIDTH, 60);
                    } else {
                        this.dragOffset = cc.v2(0, 60 + WIDTH);
                    }
                    linkCell = cell.pair;
                } else if (cell.type == CellType.竖向连接) {
                    this.dragOffset = cc.v2(0, 75);
                    linkCell = cell;
                } else if (cell.type == CellType.横向连接) {
                    this.dragOffset = cc.v2(0, 60);
                    linkCell = cell;
                }

                if (linkCell) {
                    this.dragCell = linkCell;

                    linkCell.node.zIndex = 100;

                    let loc = this.node.convertToNodeSpaceAR(e.getLocation());
                    this.dragTween?.stop();
                    this.dragTween = cc.tween(this.dragCell.node)
                        .to(0.2, {position: cc.v3(loc.x + this.dragOffset.x, loc.y + this.dragOffset.y, 0)}, {easing: 'sineOut'})
                        .start();

                    for (let c of linkCell.node.children) {
                        cc.tween(c)
                            .to(0.1, {scale: 0.9}, {easing: 'sineOut'})
                            .to(0.1, {scale: 1}, {easing: 'sineOut'})
                            .start();
                    }
                }

                if (cell.type == CellType.横向炸弹 ||
                    cell.type == CellType.竖向炸弹 ||
                    cell.type == CellType.圆炸弹) {
                    this.dragOffset = cc.v2(0, 0);
                    this.bombCell = cell;
                    this.dragCell = null;
                } else {
                    this.bombCell = null;
                }
            }
        }
    }

    onTouchEnd(e: cc.Event.EventTouch) {
        if (!this.touchable) {
            return;
        }

        let idx = this.touchToIdx(e.getLocation(), this.dragOffset);
        if (this.dragCell) {
            if (idx < 0) {
                idx = this.dragCell.index;
            }
            if (this.dragCell.type == CellType.数字 && this.cells[idx] != null) {
                idx = this.dragCell.index;
            }

            if (this.dragCell.type == CellType.横向连接) {
                if ((idx % 5) == 4 ||
                    (idx != this.dragCell.index && this.cells[idx + 1] && this.cells[idx + 1] != this.dragCell) ||
                    (idx != this.dragCell.index && this.cells[idx] && this.cells[idx] != this.dragCell.pair)) {
                    idx = this.dragCell.index;
                }
            } else if (this.dragCell.type == CellType.竖向连接) {
                if (Math.floor(idx / 5) == 4 ||
                    (idx != this.dragCell.index && this.cells[idx + 5] && this.cells[idx + 5] != this.dragCell) ||
                    (idx != this.dragCell.index && this.cells[idx] && this.cells[idx] != this.dragCell.pair)) {
                    idx = this.dragCell.index;
                }
            }

            this.touchable = false;
            let sameCell = idx == this.dragCell.index;

            let targetPos = cc.v3((idx % 5) * WIDTH - 2 * WIDTH, WIDTH * 2 - Math.floor(idx / 5) * WIDTH, 0);
            cc.tween(this.dragCell.node)
                .to(0.2, {position: targetPos})
                .set({zIndex: 1})
                .call(async () => {
                    if (!sameCell) {
                        let ok = await this.checkCell(idx);
                        if (!ok) {
                            this.combo = 0;
                        }
                        await this.createRandomCell(true);
                        this.touchable = true;
                    } else {
                        this.touchable = true;
                    }
                })
                .start();
            this.cells[this.dragCell.index] = null;
            if (this.dragCell.type == CellType.横向连接) {
                this.cells[this.dragCell.index + 1] = null;
                this.cells[idx + 1] = this.dragCell.pair;
                this.dragCell.pair.index = idx + 1;
            } else if (this.dragCell.type == CellType.竖向连接) {
                this.cells[this.dragCell.index + 5] = null;
                this.cells[idx + 5] = this.dragCell.pair;
                this.dragCell.pair.index = idx + 5;
            }
            this.cells[idx] = this.dragCell;
            this.dragCell.index = idx;
        }
        for (let i = 0; i < 25; i++) {
            this.bgFrames[i].active = false;
        }
        this.dragCell = null;


        if (this.bombCell && idx == this.bombCell.index) {
            this.bombCell = null;
            this.bomb(idx);
        }
    }

    bomb(idx: number): Promise<void> {

        this.touchable = false;
        let pos = this.cells[idx].node.position;

        let arr: number[] = [];
        let bombArr: Cell[] = [];

        this._getBombCells(idx, arr, bombArr);
        for (let bomb of bombArr) {
            // TODO 播放炸弹动画
            bomb.node.destroy();
            this.cells[bomb.index] = null;
        }
        if (arr.length > 0) {
            let scoreInc = 0;
            this.removeLinks(arr);
            for (let idx of arr) {
                this.cells[idx].node.destroy();
                scoreInc += this.cells[idx].num;
                this.cells[idx] = null;

            }
            if (scoreInc > 0) {
                this.showIncScore(scoreInc, pos);
            }
        }

        return new Promise<void>(resolve => {
            this.scheduleOnce(async () => {
                await this.createRandomCell(true);
                this.touchable = true;
                resolve();
            }, 0.3);
        });
    }

    _getBombCells(idx: number, arr: number[], bombArr: Cell[]) {
        let bombCell = this.cells[idx];
        let newBomb: Cell[] = [];
        let checkIdx = (idx: number) => {
            let c = this.cells[idx];
            if (c) {
                if (c.num) {
                    if (arr.indexOf(idx) < 0) {
                        arr.push(idx);
                    }
                } else if (c.isBomb) {
                    if (bombArr.indexOf(c) < 0) {
                        bombArr.push(c);
                        newBomb.push(c);
                    }
                }
            }
        };

        let checkXY = (x: number, y: number) => {
            if (x >= 0 && x < 5 && y >= 0 && y < 5) {
                let idx = y * 5 + x;
                checkIdx(idx);
            }
        }

        if (bombCell.type == CellType.横向炸弹) {
            let y = Math.floor(bombCell.index / 5);
            for (let i = 0; i < 5; i++) {
                let idx = y * 5 + i;
                checkIdx(idx);
            }
        } else if (bombCell.type == CellType.竖向炸弹) {
            let x = bombCell.index % 5;
            for (let i = 0; i < 5; i++) {
                let idx = i * 5 + x;
                let c = this.cells[idx];
                checkIdx(idx);
            }
        } else if (bombCell.type == CellType.圆炸弹) {
            let x = bombCell.index % 5;
            let y = Math.floor(bombCell.index / 5);
            checkXY(x - 1, y);
            checkXY(x + 1, y);
            checkXY(x - 1, y - 1);
            checkXY(x, y - 1);
            checkXY(x + 1, y - 1);
            checkXY(x - 1, y + 1);
            checkXY(x, y + 1);
            checkXY(x + 1, y + 1);
            checkXY(x, y);
        }

        if (newBomb.length > 0) {
            for (let c of newBomb) {
                this._getBombCells(c.index, arr, bombArr);
            }
        }
    }

    onTouchMove(e: cc.Event.EventTouch) {
        if (!this.touchable) {
            return;
        }
        if (this.dragCell) {
            let loc = this.node.convertToNodeSpaceAR(e.getLocation());

            this.dragTween?.stop();
            this.dragTween = null;
            this.dragCell.node.position = cc.v3(loc.x + this.dragOffset.x, loc.y + this.dragOffset.y, 0);


            let idx = this.touchToIdx(e.getLocation(), this.dragOffset);
            let highlightCells: number[] = null;
            let validate = idx >= 0;
            if (validate && this.dragCell.type == CellType.横向连接) {
                if ((idx % 5) == 4 ||
                    (idx != this.dragCell.index && this.cells[idx + 1] && this.cells[idx + 1] != this.dragCell) ||
                    (idx != this.dragCell.index && this.cells[idx] && this.cells[idx] != this.dragCell.pair)) {
                    validate = false;
                } else {
                    highlightCells = [idx, idx + 1];
                }
            }
            if (validate && this.dragCell.type == CellType.竖向连接) {
                if (Math.floor(idx / 5) == 4 ||
                    (idx != this.dragCell.index && this.cells[idx + 5] && this.cells[idx + 5] != this.dragCell) ||
                    (idx != this.dragCell.index && this.cells[idx] && this.cells[idx] != this.dragCell.pair)) {
                    validate = false;
                } else {
                    highlightCells = [idx, idx + 5];
                }
            }
            if (validate && this.dragCell.type == CellType.数字) {
                if (this.cells[idx] && idx != this.dragCell.index) {
                    validate = false;
                } else {
                    highlightCells = [idx];
                }
            }
            if (validate) {

                for (let i = 0; i < 25; i++) {
                    this.bgFrames[i].active = highlightCells.indexOf(i) >= 0;
                }
            }
        }
    }

    // 计算点击的格子索引
    touchToIdx(e: cc.Vec2, offset: cc.Vec2 = null): number {
        if (offset) {
            e = e.add(offset);
        }
        let loc = this.node.convertToNodeSpaceAR(e);
        loc.addSelf(cc.v2(WIDTH * 2.5, WIDTH * -2.5));
        loc.mulSelf(1 / WIDTH);
        let x = Math.floor(loc.x);
        let y = Math.floor(-loc.y);
        if (x < 0 || x > 4 || y < 0 || y > 4) {
            return -1;
        }
        return x + y * 5;
    }


    createNumCellDirect(idx: number, v: number): boolean {
        if (this.cells[idx]) {
            return false;
        }

        let node = new cc.Node();
        let sprite = node.addComponent(cc.Sprite);
        sprite.spriteFrame = this.numFrames[v - 1];
        sprite.sizeMode = cc.Sprite.SizeMode.RAW;
        node.x = (idx % 5) * WIDTH - WIDTH * 2;
        node.y = WIDTH * 2 - Math.floor(idx / 5) * WIDTH;

        let cell = node.addComponent(Cell);
        cell.type = CellType.数字;
        cell.num = v;
        cell.index = idx;
        this.cells[idx] = cell;
        this.node.addChild(node);
        return true;
    }

    // 创建数字格子
    createNumCell(idx: number, v: number, animate = false): Promise<boolean> {
        let ok = this.createNumCellDirect(idx, v);

        if (ok && animate) {
            return new Promise<boolean>(resolve => {
                let node = this.cells[idx].node;
                cc.tween(node)
                    .to(0.1, {scale: 1.1}, {easing: 'sineOut'})
                    .to(0.1, {scale: 1}, {easing: 'sineOut'})
                    .delay(0.1)
                    .call(() => {
                        resolve(true);
                    })
                    .start();
            });
        }
        return Promise.resolve(ok);
    }

    createLinkCellDirect(idx: number, linkType: CellType, v1: number, v2: number): boolean {
        if (this.cells[idx]) {
            return false;
        }
        let xPos = idx % 5;
        let yPos = Math.floor(idx / 5);

        if (linkType == CellType.横向连接) {
            if (xPos == 4) {
                return false;
            }
            if (this.cells[idx + 1]) {
                return false;
            }
        }
        if (linkType == CellType.竖向连接) {
            if (yPos == 4) {
                return false;
            }
            if (this.cells[idx + 5]) {
                return false;
            }
        }

        let node = new cc.Node();
        node.x = (idx % 5) * WIDTH - WIDTH * 2;
        node.y = WIDTH * 2 - Math.floor(idx / 5) * WIDTH;

        let cell = node.addComponent(Cell);
        cell.type = linkType;
        cell.num = v1;
        cell.index = idx;

        let linkNode = new cc.Node();
        linkNode.name = 'link';
        let link = linkNode.addComponent(cc.Sprite);
        link.sizeMode = cc.Sprite.SizeMode.RAW;
        link.trim = false;
        link.spriteFrame = this.linkFrames[linkType == CellType.横向连接 ? 0 : 1];
        node.addChild(linkNode);


        let sp1Node = new cc.Node();
        sp1Node.name = 'n1';
        let sp1 = sp1Node.addComponent(cc.Sprite);
        sp1.sizeMode = cc.Sprite.SizeMode.RAW;
        sp1.trim = false;
        sp1.spriteFrame = this.numFrames[v1 - 1];
        node.addChild(sp1Node);

        let sp2Node = new cc.Node();
        sp2Node.name = 'n2';
        let sp2 = sp2Node.addComponent(cc.Sprite);
        sp2.sizeMode = cc.Sprite.SizeMode.RAW;
        sp2.trim = false;
        sp2.spriteFrame = this.numFrames[v2 - 1];
        let cell2 = sp2Node.addComponent(Cell);
        cell2.type = CellType.连接部分;
        cell2.num = v2;
        node.addChild(sp2Node);

        this.node.addChild(node);

        this.cells[idx] = cell;
        cell2.pair = cell;
        cell.pair = cell2;

        if (linkType == CellType.横向连接) {
            linkNode.position = cc.v3(75, 0, 0);
            sp2Node.position = cc.v3(WIDTH, 0, 0);
            cell2.index = idx + 1;
            this.cells[idx + 1] = cell2;
        } else {
            linkNode.position = cc.v3(0, -75, 0);
            sp2Node.position = cc.v3(0, -WIDTH, 0);
            cell2.index = idx + 5;
            this.cells[idx + 5] = cell2;
        }
        return true;
    }


    // 创建连接格子
    async createLinkCell(idx: number, linkType: CellType, v1: number, v2: number, animate = false): Promise<Cell> {
        let ok = this.createLinkCellDirect(idx, linkType, v1, v2);
        if (ok && animate) {
            let cell = this.cells[idx];
            let sp1Node = cell.node.getChildByName('n1');
            let sp2Node = cell.node.getChildByName('n2');
            for (let n of [sp1Node, sp2Node]) {
                cc.tween(n)
                    .to(0.1, {scale: 1.1}, {easing: 'sineOut'})
                    .to(0.1, {scale: 1}, {easing: 'sineOut'})
                    .start();
            }
            return new Promise<Cell>(resolve => {
                this.scheduleOnce(() => {
                    resolve(cell);
                }, 0.3);
            });
        }
        return null;
    }

    // 检查指定的格子是否可以合并
    async checkCell(idx: number, skipPair: boolean = false): Promise<boolean> {
        let cell = this.cells[idx];
        if (!cell) {
            return false;
        }

        let ok = false;
        if (!skipPair &&
            (cell.type == CellType.横向连接 || cell.type == CellType.竖向连接) && cell.num != cell.pair.num) {
            ok = await this.checkCell(cell.pair.index);
            cell = this.cells[idx];
        }

        if (cell && cell.num) {
            let arr = this.getLinkedCells(idx, cell.num);
            if (arr.length >= 3) {
                await this.merge(arr, true);
                await this.checkCell(arr[0]);
                ok = true;
            }
        }
        return ok;
    }

    // 合并指定的格子
    merge(arr: number[], generateBomb: boolean): Promise<void> {
        return new Promise<void>(resolve => {
            this.removeLinks(arr);
            let firstCell = this.cells[arr[0]];

            for (let idx of arr) {
                let cell = this.cells[idx];
                if (cell != firstCell) {
                    cc.tween(cell.node)
                        .to(0.25, {position: firstCell.node.position}, {easing: 'sineOut'})
                        .start();
                }
            }

            this.scheduleOnce(async () => {
                for (let idx of arr) {
                    let cell = this.cells[idx];
                    cell.node.destroy();

                    this.cells[idx] = null;
                }

                if (generateBomb && arr.length >= 5) {
                    await this.createBom(firstCell.index, Math.random() < 0.5 ? CellType.横向炸弹 : CellType.竖向炸弹, true);
                } else if (firstCell.num < 9) {
                    await this.createNumCell(firstCell.index, firstCell.num + 1, true);
                } else {
                    await this.createBom(firstCell.index, CellType.圆炸弹, true);
                }

                this.combo++;
                if (this.combo > 1) {

                    let text = ['漂亮', '炫酷', '真棒', '厉害', '完美', '优秀', '天才'][Math.min(this.combo - 2, 6)];
                    this.comboLabel.string = text + '×' + this.combo;


                    cc.Tween.stopAllByTarget(this.comboLabel.node);
                    this.comboLabel.node.active = true;
                    cc.tween(this.comboLabel.node)
                        .to(0.1, {scale: 1.1}, {easing: 'sineOut'})
                        .to(0.1, {scale: 1}, {easing: 'sineOut'})
                        .delay(1.5)
                        .call(() => this.comboLabel.node.active = false)
                        .start();
                }

                let scoreInc = firstCell.num * 10 * (arr.length + Math.max(0, this.combo - 1));

                this.showIncScore(scoreInc, this.cells[arr[0]].node.position);


                this.mergeTimes++;

                resolve();

            }, 0.3);
        });
    }

    // 显示加分效果
    showIncScore(scoreInc: number, pos: cc.Vec3) {
        this.score += scoreInc;

        let scNode = new cc.Node();
        scNode.position = pos.add(cc.v3(0, 30, 0));
        scNode.zIndex = 10000;
        let lb = scNode.addComponent(cc.Label);
        lb.fontSize = 60;
        lb.lineHeight = 100;
        lb.string = '+' + scoreInc;

        let outline = scNode.addComponent(cc.LabelOutline);
        outline.width = 5;
        outline.color = new cc.Color(20, 30, 180, 100);

        this.node.addChild(scNode);
        cc.tween(scNode)
            .by(0.2, {position: cc.v3(0, 50, 0)})
            .delay(0.8)
            .call(() => {
                this.scoreLabel.string = '' + this.score;
                let topScore = parseInt(cc.sys.localStorage.getItem('topScore')) | 0;
                if (this.score > topScore) {
                    cc.sys.localStorage.setItem('topScore', this.score.toString());
                    this.topScoreLabel.string = this.scoreLabel.string;
                }
                scNode.destroy();
            })
            .start();
    }

    // 断开连接
    removeLinks(arr: number[]) {
        for (let idx of arr) {
            let cell = this.cells[idx];
            if (!cell) {
                continue;
            }

            if (cell.type == CellType.连接部分) {
                cell = cell.pair;
            }
            if (cell.type == CellType.横向连接 || cell.type == CellType.竖向连接) {
                cell.type = CellType.数字;
                cell.pair.type = CellType.数字;

                let node2 = cell.node.getChildByName('n2');
                let wp = cell.node.convertToWorldSpaceAR(node2.position);
                cell.node.removeChild(node2, false);
                this.node.addChild(node2);
                node2.position = this.node.convertToNodeSpaceAR(wp);

                let link = cell.node.getChildByName('link');
                link.destroy();

                let node1 = cell.node.getChildByName('n1');
                node1.destroy();

                let sp = cell.node.addComponent(cc.Sprite);
                sp.sizeMode = cc.Sprite.SizeMode.RAW;
                sp.trim = false;
                sp.spriteFrame = this.numFrames[cell.num - 1];
            }
        }
    }

    // 获取相连的格子
    getLinkedCells(idx: number, num: number, arr: number[] = null, skipIdx = -1) {
        if (arr == null) {
            arr = [];
        }

        let cell = this.cells[idx];
        if (!cell || !cell.num || cell.num != num || arr.indexOf(idx) >= 0) {
            return arr;
        }
        arr.push(idx);

        if (idx >= 5 && idx - 5 != skipIdx) {
            this.getLinkedCells(idx - 5, num, arr, idx);
        }
        if (idx < 20 && idx + 5 != skipIdx) {
            this.getLinkedCells(idx + 5, num, arr, idx);
        }
        if ((idx % 5) > 0 && idx - 1 != skipIdx) {
            this.getLinkedCells(idx - 1, num, arr, idx);
        }
        if ((idx % 5) < 4 && idx + 1 != skipIdx) {
            this.getLinkedCells(idx + 1, num, arr, idx);
        }
        return arr;
    }

    // 随机生成1次格子
    async createRandomCell(animate = false): Promise<boolean> {
        let emptyIdx = new Array<number>();
        for (let idx = 0; idx < 25; idx++) {
            if (!this.cells[idx]) {
                emptyIdx.push(idx);
            }
        }
        if (emptyIdx.length == 0) {
            this.checkGameOver();
            return false;
        }
        let idx = emptyIdx[Math.floor(Math.random() * emptyIdx.length)];

        let maxNum = 4;
        for (let c of this.cells) {
            if (c && c.num) {
                if (c.num > maxNum) {
                    maxNum = c.num;
                }
            }
        }
        if (maxNum < 4) {
            maxNum = 4;
        }
        if (maxNum > 8) {
            maxNum = 8;
        }
        let num = Math.floor(Math.random() * maxNum + 1);
        let type: CellType = null;

        while (type == null) {
            let ran = Math.random();
            if (ran < 0.3) {
                type = CellType.数字;
            } else if (ran < 0.65) {
                type = CellType.横向连接;
                if ((idx % 5) == 4 || this.cells[idx + 1]) {
                    type = null;
                }
            } else {
                type = CellType.竖向连接;
                if (Math.floor(idx / 5) == 4 || this.cells[idx + 5]) {
                    type = null;
                }
            }
        }
        if (type == CellType.数字) {
            if (await this.createNumCell(idx, num, animate)) {
                await this.checkCell(idx);
                this.checkGameOver();
                return true;
            }
        } else {
            let num2 = Math.floor(Math.random() * maxNum + 1);
            let c = await this.createLinkCell(idx, type, num, num2, animate);
            if (c) {
                await this.checkCell(c.index);
                this.checkGameOver();
                return true;
            }
        }
        return false;
    }

    // 检查是否游戏结束
    checkGameOver() {
        let gameOver = true;
        if (this.numCombine > 0) {
            gameOver = false;
        } else if (this.cells.find(v => (v && v.isBomb))) {
            gameOver = false;
        } else if (this.cells.indexOf(null) >= 0) {
            gameOver = false;
        }
        if (gameOver) {
            this.touchable = false;
            this.resultNode.active = true;
            this.resultScoreLabel.string = '' + this.score;
            let topScore = parseInt(this.topScoreLabel.string) | 0;
            this.resultTopScoreLabel.string = '' + topScore;

            let arr = this.resultHintNode.children;
            if (topScore <= this.score) {
                arr[0].getComponent(cc.Label).string = '您创造了新纪录!';
                arr[0].active = true;
                arr[1].active = false;
                arr[2].active = false;
            } else {
                arr[0].getComponent(cc.Label).string = '还差';
                arr[1].getComponent(cc.Label).string = '' + (topScore - this.score);
                arr[2].getComponent(cc.Label).string = '分破纪录';
                arr[0].active = true;
                arr[1].active = true;
                arr[2].active = true;
            }
        }
    }

    // 开局创建初始随机格子
    createInitCell() {
        let emptyIdx = new Array<number>();
        for (let idx = 0; idx < 25; idx++) {
            if (!this.cells[idx]) {
                emptyIdx.push(idx);
            }
        }
        if (emptyIdx.length == 0) {
            return null;
        }
        let idx = emptyIdx[Math.floor(Math.random() * emptyIdx.length)];
        if (this.cells[idx]) {
            return null;
        }
        let num = Math.floor(Math.random() * 4 + 1);
        let ran = Math.random();
        let type: CellType;
        if (ran < 0.4) {
            type = CellType.数字;
        } else if (ran < 0.7) {
            type = CellType.横向连接;
            if ((idx % 5) == 4 || this.cells[idx + 1]) {
                type = CellType.数字;
            }
        } else {
            type = CellType.竖向连接;
            if (Math.floor(idx / 5) == 4 || this.cells[idx + 5]) {
                type = CellType.数字;
            }
        }
        if (type == CellType.数字) {
            if (this.createNumCellDirect(idx, num)) {
                if (this.getLinkedCells(idx, num).length >= 3) {
                    this.cells[idx].node.removeFromParent(true);
                    this.cells[idx].node.destroy();
                    this.cells[idx] = null;
                }
                return this.cells[idx];
            }
        } else {
            if (this.createLinkCellDirect(idx, type, num, num)) {
                if (this.getLinkedCells(idx, num).length >= 3) {
                    this.cells[idx].node.removeFromParent(true);
                    this.cells[idx].node.destroy();
                    this.cells[this.cells[idx].pair.index] = null;
                    this.cells[idx] = null;
                }
                return this.cells[idx];
            }
        }
        return null;
    }

    // 在指定位置添加一个炸弹
    async createBom(idx: number, type: CellType, animate = false): Promise<boolean> {
        if (this.cells[idx]) {
            return false;
        }
        if (this.cells[idx]) {
            return false;
        }

        let node = new cc.Node();
        let sprite = node.addComponent(cc.Sprite);
        sprite.spriteFrame = this.bomFrames[type == CellType.圆炸弹 ? 0 : (type == CellType.横向炸弹 ? 1 : 2)];
        sprite.sizeMode = cc.Sprite.SizeMode.RAW;
        node.x = (idx % 5) * WIDTH - WIDTH * 2;
        node.y = WIDTH * 2 - Math.floor(idx / 5) * WIDTH;

        let cell = node.addComponent(Cell);
        cell.type = type;
        cell.index = idx;
        this.cells[idx] = cell;
        this.node.addChild(node);

        if (animate) {
            return new Promise<boolean>(resolve => {
                cc.tween(node)
                    .to(0.1, {scale: 1.1}, {easing: 'sineOut'})
                    .to(0.1, {scale: 1}, {easing: 'sineOut'})
                    .call(() => {
                        resolve(true);
                    })
                    .start();
            });
        }
        return true;
    }

    // 显示道具1的选框
    showClickBox1() {
        if (this.numCombine > 0) {
            this.clickBox.show1();
        } else {
            // 道具数量不足, 显示广告
        }
    }

    // 显示道具2的选框
    showClickBox2() {
        if (this.numCut > 0) {
            this.clickBox.show2();
        } else {
            // 道具数量不足, 显示广告
        }
    }

    // 使用道具的回调
    async onClickBox(idx: number, type: string) {
        if (type == '1') {
            // 合并数字
            let cell = this.cells[idx];
            if (cell && cell.num) {
                this.numCombine--;
                this.updateItemLabelText();

                let arr: number[] = [idx];
                for (let i = 0; i < 25; i++) {
                    if (i != idx) {
                        let c = this.cells[i];
                        if (c && c.num && c.num == cell.num) {
                            arr.push(c.index);
                        }
                    }
                }
                this.clickBox.close();

                this.touchable = false;
                await this.merge(arr, false);
                await this.checkCell(idx);
                await this.createRandomCell(true);
                this.touchable = true;

            }
        } else if (type == '2') {
            // 删除连接
            this.numCut--;
            this.updateItemLabelText();

            this.clickBox.close();
            let arr: number[] = [idx];
            for (let i = 0; i < 25; i++) {
                if (i != idx) {
                    let c = this.cells[i];
                    if (c && c.type == CellType.连接部分) {
                        arr.push(c.index);
                    }
                }
            }
            this.touchable = false;
            this.removeLinks(arr);

            let n = 0;
            for (let i = 0; i < 25; i++) {
                let c = this.cells[i];
                if (c && c.num) {
                    cc.tween(c.node)
                        .delay((n++) * 0.04)
                        .to(0.1, {scale: 1.1}, {easing: 'sineOut'})
                        .to(0.1, {scale: 1}, {easing: 'sineOut'})
                        .start();
                }
            }
            this.scheduleOnce(() => {
                this.touchable = true;
            }, n * 0.04);


        }
    }

    updateItemLabelText() {
        this.combineLabel.string = 'x' + this.numCombine;
        this.cutLabel.string = 'x' + this.numCut;
    }

    reload() {
        cc.director.loadScene('game');
    }


    // 清除所有格子,并且随机生成一次
    clear() {
        this.node.destroyAllChildren();
        this.cells = new Array(25);
        this.createRandomCell(true);
    }
}
